#include "STreeWidget.h"

#include <core/StyleMgr.h>

#include <QAbstractItemView>
#include <QColor>

const int treeDataRole = Qt::UserRole + 1;
/// //////////////////////////////////////////////////////////
/// //////////////////////////////////////////////////////////
/// <STreeData>
STreeData::STreeData() : m_pParent(nullptr) {}

STreeData::~STreeData() {}

void STreeData::addChild(STreeData& data) {
  data.m_pParent = this;
  m_Children.push_back(data);
}

void STreeData::addChild(const QString& szText, const QString& szData,
                         bool check) {
  STreeData data;
  data.m_szText = szText;
  data.m_szData = szData;
  data.m_check = check;
  addChild(data);
}

int STreeData::getChildCount() { return m_Children.size(); }

STreeData& STreeData::getChild(int i) {
  static STreeData dataEmpty;
  if (i >= 0 && i < (int)m_Children.size()) return m_Children[i];
  return dataEmpty;
}

STreeData* STreeData::getParent() { return m_pParent; }

/// //////////////////////////////////////////////////////////
/// //////////////////////////////////////////////////////////
/// <STreeWidget>
STreeWidget::STreeWidget(QWidget* parent /*= nullptr*/) : QTreeWidget(parent) {
  m_onSetting = false;
  m_limitWidth = 0;

  QString styleSheet =
      QString(
          "QTreeView							"
          "{color:#%1;background-color:#%2;border:0px;padding:0px;}"
          "QTreeView::item					"
          "{color:#%1;background-color:#%2;padding:0px;margin:0px}"

          "QTreeView::branch						"
          "{width:8px;background-color:transparent;padding:0px;margin:0px}"
          "QTreeView::branch:open:has-children	"
          "{image:url(:/widgets/image/dropdown_down/dropdown_down_normal.png);}"
          "QTreeView::branch:closed:has-children	"
          "{image:url(:/widgets/image/angle_bracket_right_mini/"
          "angle_bracket_right_mini_normal.png);}"

          "QTreeWidget::indicator					"
          "		{width:16px;height:16px;padding:0px;margin:0px}"
          "QTreeWidget::indicator:enabled:unchecked		"
          "{image:url(:/widgets/image/check/check_normal.png);}"
          "QTreeWidget::indicator:enabled:checked			"
          "{image:url(:/widgets/image/check_selected/"
          "check_selected_normal.png);}"
          "QTreeWidget::indicator:enabled:indeterminate	"
          "{image:url(:/widgets/image/check_part/check_part_normal.png);}")
          .arg(StyleMgr::instance().color("TextNormal").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("BackNormal").rgb(), 0, 16);

  setStyleSheet(styleSheet);
  setIndentation(16);
  setHeaderHidden(true);
  setSelectionMode(QAbstractItemView::NoSelection);

  connect(this, &QTreeWidget::itemChanged, this,
          &STreeWidget::onTreeItemChanged);
}

STreeWidget::~STreeWidget() {}

void STreeWidget::setTreeData(STreeData& treeData, QTreeWidgetItem* parent) {
  if (!parent) {
    //		this->clear();
    startSetting();
  }

  int count = treeData.getChildCount();
  for (int i = 0; i < count; i++) {
    STreeData& data = treeData.getChild(i);

    QStringList lstText;
    lstText.push_back(data.m_szText);
    QTreeWidgetItem* item;
    if (!parent)
      item = new QTreeWidgetItem(this, lstText);  // 第一层
    else
      item = new QTreeWidgetItem(parent, lstText);
    Qt::ItemFlags flg = item->flags();
    flg |= Qt::ItemIsUserCheckable;
    flg &= ~Qt::ItemIsSelectable;
    item->setFlags(flg);
    item->setData(0, treeDataRole, data.m_szData);

    if (data.m_check) {
      item->setCheckState(0, Qt::Checked);
    } else {
      item->setCheckState(0, Qt::Unchecked);
    }

    if (m_limitWidth > 0 && fontMetrics().width(data.m_szText) > m_limitWidth) {
      item->setToolTip(0, data.m_szText);
    }

    setTreeData(data, item);
  }
  if (!parent) endSetting();
}

void STreeWidget::clearSelect() {
  startSetting();
  int count = topLevelItemCount();
  for (int i = 0; i < count; i++) {
    QTreeWidgetItem* item = topLevelItem(i);
    clearSelect(item);
  }
  endSetting();
  emit itemCheckChanged();
}

void STreeWidget::clearSelect(QTreeWidgetItem* item) {
  if (!item) return;
  int count = item->childCount();
  for (int i = 0; i < count; i++) {
    QTreeWidgetItem* pChild = item->child(i);
    clearSelect(pChild);
  }
  item->setCheckState(0, Qt::Unchecked);
}

void STreeWidget::onTreeItemChanged(QTreeWidgetItem* item, int column) {
  if (m_onSetting) return;
  if (!item) return;

  static long itemAddr = 0;
  if (itemAddr == 0) {
    itemAddr = (long)item;
    updateChildItem(item);
    updateParentItem(item);
    itemAddr = 0;
    emit itemCheckChanged();
  } else if (itemAddr != (long)item) {
    updateChildItem(item);
    updateParentItem(item);
  }
}

void STreeWidget::updateParentItem(QTreeWidgetItem* item) {
  // 更新父对象的勾选状态
  if (item == nullptr) return;
  Qt::CheckState status = item->checkState(0);
  QTreeWidgetItem* pParent = item->parent();
  if (pParent != 0) {
    int count = pParent->childCount();
    bool hasCheck = false;
    bool hasUnCheck = false;
    for (int i = 0; i < count; ++i) {
      QTreeWidgetItem* pChild = pParent->child(i);
      if (!pChild) continue;
      Qt::CheckState st1 = pChild->checkState(0);
      switch (st1) {
        case Qt::Unchecked:
          hasUnCheck = true;
          break;
        case Qt::PartiallyChecked:
          hasCheck = true;
          hasUnCheck = true;
          break;
        case Qt::Checked:
          hasCheck = true;
          break;
        default:
          break;
      }
      if (hasCheck && hasUnCheck) break;
    }
    Qt::CheckState st0 = pParent->checkState(0);
    Qt::CheckState st2;
    if (!hasCheck)
      st2 = Qt::Unchecked;
    else if (!hasUnCheck)
      st2 = Qt::Checked;
    else
      st2 = Qt::PartiallyChecked;

    if (st2 != st0) {
      pParent->setCheckState(0, st2);
    }
  }
}

void STreeWidget::updateChildItem(QTreeWidgetItem* item) {
  // 更新zi对象的勾选状态
  if (item == nullptr) return;
  Qt::CheckState status = item->checkState(0);
  if (status == Qt::PartiallyChecked) return;  // 部分选中
  int count = item->childCount();
  for (int i = 0; i < count; ++i) {
    QTreeWidgetItem* pChild = item->child(i);
    if (!pChild) continue;
    Qt::CheckState st0 = pChild->checkState(0);
    if (st0 != status) {
      pChild->setCheckState(0, status);
    }
  }
}

void STreeWidget::invertCheck() {
  startSetting();
  int count = topLevelItemCount();
  for (int i = 0; i < count; i++) {
    QTreeWidgetItem* item = topLevelItem(i);
    invertCheck(item);
  }
  endSetting();
  emit itemCheckChanged();
}

void STreeWidget::invertCheck(QTreeWidgetItem* item) {
  if (!item) return;
  int count = item->childCount();
  for (int i = 0; i < count; i++) {
    QTreeWidgetItem* pChild = item->child(i);
    invertCheck(pChild);
  }
  Qt::CheckState status = item->checkState(0);
  switch (status) {
    case Qt::Unchecked:
      item->setCheckState(0, Qt::Checked);
      break;
    case Qt::Checked:
      item->setCheckState(0, Qt::Unchecked);
      break;
    case Qt::PartiallyChecked:
    default:
      break;
  }
}

bool STreeWidget::getSelectItemText(QStringList& lstText) {
  lstText.clear();
  m_data.clear();
  int count = topLevelItemCount();
  for (int i = 0; i < count; i++) {
    QTreeWidgetItem* item = topLevelItem(i);
    getSelectItemText(item, lstText);
  }

  return true;
}

void STreeWidget::getSelectItemText(QTreeWidgetItem* item,
                                    QStringList& lstText) {
  if (!item) return;
  int count = item->childCount();
  if (count > 0) {
    for (int i = 0; i < count; i++) {
      QTreeWidgetItem* pChild = item->child(i);
      getSelectItemText(pChild, lstText);
    }
    return;
  }

  if (Qt::Checked == item->checkState(0)) {
    lstText.push_back(item->text(0));
    QVariant var = item->data(0, treeDataRole);
    QString szData = var.toString();
    m_data.push_back(szData);
  }
}

const QStringList& STreeWidget::getSelectItemData() {
  m_data.clear();
  QStringList lstSelText;
  getSelectItemText(lstSelText);

  return m_data;
}
